/**************************************************************************

    A/V Stream Camera Sample

    Copyright (c) 2014, Microsoft Corporation.

    File:

        Synthesizer.cpp

    Abstract:

        This file contains the implementation of CSynthesizer.

        The base image synthesis and overlay class.  These classes provide
        image synthesis (pixel, color-bar, etc...) onto buffers of various
        formats.

        Internally, all CSynthesizer objects represent a pixel as a 32 bit
        quantity with 8 bits per sample.  The base CSynthesizer implements
        all rendering functionality with this assumption in mind.  It
        simplifies rendering substantially and means we do not need to re-
        implement rendering functions for each format.  
        
        Most end formats can be synthesized from this uncompressed format 
        with overhead that is slightly worse than a copy.  Color spaces are
        handled by using a rendering palette that is unique for each.

    History:

        created 04/14/2014

**************************************************************************/

#include "Common.h"

/**************************************************************************

    PAGED CODE

**************************************************************************/

#ifdef ALLOC_PRAGMA
#pragma code_seg("PAGE")
#endif // ALLOC_PRAGMA

/**************************************************************************

    Constants

**************************************************************************/

//
// Standard definition of EIA-189-A color bars.  The actual color definitions
// are either in CRGB24Synthesizer or CYUVSynthesizer.
//

const COLOR CSynthesizer::m_ColorBars[8] =
{MAGENTA, BLUE, GREEN, BLACK, WHITE, YELLOW, RED, CYAN };


//
//  Corner registration block colors.
//
const COLOR g_TopLeft  = GREY;
const COLOR g_TopRight = BLUE;
const COLOR g_BotLeft  = RED;
const COLOR g_BotRight = GREEN;

//
// The following is an 8x8 bitmapped font for use in the text overlay
// code.
//
const UCHAR
CSynthesizer::
m_FontData [2][256][8] =
{
  {
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e},
    {0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e},
    {0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00},
    {0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00},
    {0x38, 0x7c, 0x38, 0xfe, 0xfe, 0x7c, 0x38, 0x7c},
    {0x10, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x7c},
    {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00},
    {0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff},
    {0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00},
    {0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff},
    {0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78},
    {0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18},
    {0x3f, 0x33, 0x3f, 0x30, 0x30, 0x70, 0xf0, 0xe0},
    {0x7f, 0x63, 0x7f, 0x63, 0x63, 0x67, 0xe6, 0xc0},
    {0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99},
    {0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00},
    {0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00},
    {0x18, 0x3c, 0x7e, 0x18, 0x18, 0x7e, 0x3c, 0x18},
    {0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00},
    {0x7f, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x00},
    {0x3e, 0x63, 0x38, 0x6c, 0x6c, 0x38, 0xcc, 0x78},
    {0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00},
    {0x18, 0x3c, 0x7e, 0x18, 0x7e, 0x3c, 0x18, 0xff},
    {0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x00},
    {0x18, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00},
    {0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00},
    {0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00},
    {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00},
    {0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00},
    {0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x00, 0x00},
    {0x00, 0xff, 0xff, 0x7e, 0x3c, 0x18, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x30, 0x78, 0x78, 0x30, 0x30, 0x00, 0x30, 0x00},
    {0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00},
    {0x30, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x30, 0x00},
    {0x00, 0xc6, 0xcc, 0x18, 0x30, 0x66, 0xc6, 0x00},
    {0x38, 0x6c, 0x38, 0x76, 0xdc, 0xcc, 0x76, 0x00},
    {0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00},
    {0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00},
    {0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00},
    {0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x60},
    {0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00},
    {0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00},
    {0x7c, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0x7c, 0x00},
    {0x30, 0x70, 0x30, 0x30, 0x30, 0x30, 0xfc, 0x00},
    {0x78, 0xcc, 0x0c, 0x38, 0x60, 0xcc, 0xfc, 0x00},
    {0x78, 0xcc, 0x0c, 0x38, 0x0c, 0xcc, 0x78, 0x00},
    {0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00},
    {0xfc, 0xc0, 0xf8, 0x0c, 0x0c, 0xcc, 0x78, 0x00},
    {0x38, 0x60, 0xc0, 0xf8, 0xcc, 0xcc, 0x78, 0x00},
    {0xfc, 0xcc, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00},
    {0x78, 0xcc, 0xcc, 0x78, 0xcc, 0xcc, 0x78, 0x00},
    {0x78, 0xcc, 0xcc, 0x7c, 0x0c, 0x18, 0x70, 0x00},
    {0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x00},
    {0x00, 0x30, 0x30, 0x00, 0x00, 0x30, 0x30, 0x60},
    {0x18, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x18, 0x00},
    {0x00, 0x00, 0xfc, 0x00, 0x00, 0xfc, 0x00, 0x00},
    {0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00},
    {0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00},
    {0x7c, 0xc6, 0xde, 0xde, 0xde, 0xc0, 0x78, 0x00},
    {0x30, 0x78, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0x00},
    {0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00},
    {0x3c, 0x66, 0xc0, 0xc0, 0xc0, 0x66, 0x3c, 0x00},
    {0xf8, 0x6c, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00},
    {0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00},
    {0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00},
    {0x3c, 0x66, 0xc0, 0xc0, 0xce, 0x66, 0x3e, 0x00},
    {0xcc, 0xcc, 0xcc, 0xfc, 0xcc, 0xcc, 0xcc, 0x00},
    {0x78, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00},
    {0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00},
    {0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00},
    {0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00},
    {0xc6, 0xee, 0xfe, 0xfe, 0xd6, 0xc6, 0xc6, 0x00},
    {0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00},
    {0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x00},
    {0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00},
    {0x78, 0xcc, 0xcc, 0xcc, 0xdc, 0x78, 0x1c, 0x00},
    {0xfc, 0x66, 0x66, 0x7c, 0x6c, 0x66, 0xe6, 0x00},
    {0x78, 0xcc, 0xe0, 0x70, 0x1c, 0xcc, 0x78, 0x00},
    {0xfc, 0xb4, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00},
    {0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xfc, 0x00},
    {0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00},
    {0xc6, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x00},
    {0xc6, 0xc6, 0x6c, 0x38, 0x38, 0x6c, 0xc6, 0x00},
    {0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x30, 0x78, 0x00},
    {0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00},
    {0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00},
    {0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00},
    {0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00},
    {0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff},
    {0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00},
    {0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0xdc, 0x00},
    {0x00, 0x00, 0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x00},
    {0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00},
    {0x00, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00},
    {0x38, 0x6c, 0x60, 0xf0, 0x60, 0x60, 0xf0, 0x00},
    {0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8},
    {0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00},
    {0x30, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00},
    {0x0c, 0x00, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78},
    {0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00},
    {0x70, 0x30, 0x30, 0x30, 0x30, 0x30, 0x78, 0x00},
    {0x00, 0x00, 0xcc, 0xfe, 0xfe, 0xd6, 0xc6, 0x00},
    {0x00, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0xcc, 0x00},
    {0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0x78, 0x00},
    {0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0},
    {0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e},
    {0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0xf0, 0x00},
    {0x00, 0x00, 0x7c, 0xc0, 0x78, 0x0c, 0xf8, 0x00},
    {0x10, 0x30, 0x7c, 0x30, 0x30, 0x34, 0x18, 0x00},
    {0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00},
    {0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x78, 0x30, 0x00},
    {0x00, 0x00, 0xc6, 0xd6, 0xfe, 0xfe, 0x6c, 0x00},
    {0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00},
    {0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8},
    {0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00},
    {0x1c, 0x30, 0x30, 0xe0, 0x30, 0x30, 0x1c, 0x00},
    {0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00},
    {0xe0, 0x30, 0x30, 0x1c, 0x30, 0x30, 0xe0, 0x00},
    {0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00},
    {0x78, 0xcc, 0xc0, 0xcc, 0x78, 0x18, 0x0c, 0x78},
    {0x00, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00},
    {0x1c, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00},
    {0x7e, 0xc3, 0x3c, 0x06, 0x3e, 0x66, 0x3f, 0x00},
    {0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00},
    {0xe0, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00},
    {0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00},
    {0x00, 0x00, 0x78, 0xc0, 0xc0, 0x78, 0x0c, 0x38},
    {0x7e, 0xc3, 0x3c, 0x66, 0x7e, 0x60, 0x3c, 0x00},
    {0xcc, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00},
    {0xe0, 0x00, 0x78, 0xcc, 0xfc, 0xc0, 0x78, 0x00},
    {0xcc, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00},
    {0x7c, 0xc6, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00},
    {0xe0, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00},
    {0xc6, 0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00},
    {0x30, 0x30, 0x00, 0x78, 0xcc, 0xfc, 0xcc, 0x00},
    {0x1c, 0x00, 0xfc, 0x60, 0x78, 0x60, 0xfc, 0x00},
    {0x00, 0x00, 0x7f, 0x0c, 0x7f, 0xcc, 0x7f, 0x00},
    {0x3e, 0x6c, 0xcc, 0xfe, 0xcc, 0xcc, 0xce, 0x00},
    {0x78, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00},
    {0x00, 0xcc, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00},
    {0x00, 0xe0, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00},
    {0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00},
    {0x00, 0xe0, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00},
    {0x00, 0xcc, 0x00, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8},
    {0xc3, 0x18, 0x3c, 0x66, 0x66, 0x3c, 0x18, 0x00},
    {0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00},
    {0x18, 0x18, 0x7e, 0xc0, 0xc0, 0x7e, 0x18, 0x18},
    {0x38, 0x6c, 0x64, 0xf0, 0x60, 0xe6, 0xfc, 0x00},
    {0xcc, 0xcc, 0x78, 0xfc, 0x30, 0xfc, 0x30, 0x30},
    {0xf8, 0xcc, 0xcc, 0xfa, 0xc6, 0xcf, 0xc6, 0xc7},
    {0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70},
    {0x1c, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x7e, 0x00},
    {0x38, 0x00, 0x70, 0x30, 0x30, 0x30, 0x78, 0x00},
    {0x00, 0x1c, 0x00, 0x78, 0xcc, 0xcc, 0x78, 0x00},
    {0x00, 0x1c, 0x00, 0xcc, 0xcc, 0xcc, 0x7e, 0x00},
    {0x00, 0xf8, 0x00, 0xf8, 0xcc, 0xcc, 0xcc, 0x00},
    {0xfc, 0x00, 0xcc, 0xec, 0xfc, 0xdc, 0xcc, 0x00},
    {0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 0x00},
    {0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00},
    {0x30, 0x00, 0x30, 0x60, 0xc0, 0xcc, 0x78, 0x00},
    {0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00},
    {0xc3, 0xc6, 0xcc, 0xde, 0x33, 0x66, 0xcc, 0x0f},
    {0xc3, 0xc6, 0xcc, 0xdb, 0x37, 0x6f, 0xcf, 0x03},
    {0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00},
    {0x00, 0x33, 0x66, 0xcc, 0x66, 0x33, 0x00, 0x00},
    {0x00, 0xcc, 0x66, 0x33, 0x66, 0xcc, 0x00, 0x00},
    {0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88},
    {0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa},
    {0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee},
    {0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18},
    {0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18},
    {0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18},
    {0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36},
    {0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36},
    {0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18},
    {0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36},
    {0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36},
    {0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36},
    {0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00},
    {0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00},
    {0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18},
    {0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00},
    {0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18},
    {0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18},
    {0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00},
    {0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18},
    {0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18},
    {0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36},
    {0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36},
    {0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36},
    {0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36},
    {0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00},
    {0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36},
    {0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00},
    {0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18},
    {0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36},
    {0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00},
    {0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18},
    {0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36},
    {0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36},
    {0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18},
    {0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18},
    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
    {0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff},
    {0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0},
    {0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f},
    {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x76, 0xdc, 0xc8, 0xdc, 0x76, 0x00},
    {0x00, 0x78, 0xcc, 0xf8, 0xcc, 0xf8, 0xc0, 0xc0},
    {0x00, 0xfc, 0xcc, 0xc0, 0xc0, 0xc0, 0xc0, 0x00},
    {0x00, 0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00},
    {0xfc, 0xcc, 0x60, 0x30, 0x60, 0xcc, 0xfc, 0x00},
    {0x00, 0x00, 0x7e, 0xd8, 0xd8, 0xd8, 0x70, 0x00},
    {0x00, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0xc0},
    {0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x00},
    {0xfc, 0x30, 0x78, 0xcc, 0xcc, 0x78, 0x30, 0xfc},
    {0x38, 0x6c, 0xc6, 0xfe, 0xc6, 0x6c, 0x38, 0x00},
    {0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x6c, 0xee, 0x00},
    {0x1c, 0x30, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00},
    {0x00, 0x00, 0x7e, 0xdb, 0xdb, 0x7e, 0x00, 0x00},
    {0x06, 0x0c, 0x7e, 0xdb, 0xdb, 0x7e, 0x60, 0xc0},
    {0x38, 0x60, 0xc0, 0xf8, 0xc0, 0x60, 0x38, 0x00},
    {0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x00},
    {0x00, 0xfc, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x00},
    {0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0xfc, 0x00},
    {0x60, 0x30, 0x18, 0x30, 0x60, 0x00, 0xfc, 0x00},
    {0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0xfc, 0x00},
    {0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18},
    {0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70},
    {0x30, 0x30, 0x00, 0xfc, 0x00, 0x30, 0x30, 0x00},
    {0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00},
    {0x38, 0x6c, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00},
    {0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x1c},
    {0x78, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00},
    {0x70, 0x18, 0x30, 0x60, 0x78, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
  },
  {
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x7e, 0x81, 0xa9, 0x8d, 0x8d, 0xa9, 0x81, 0x7e},
    {0x7e, 0xff, 0xd7, 0xf3, 0xf3, 0xd7, 0xff, 0x7e},
    {0x00, 0x70, 0xf8, 0xfc, 0x7e, 0xfc, 0xf8, 0x70},
    {0x00, 0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10},
    {0x00, 0x18, 0x5d, 0xff, 0xff, 0xff, 0x5d, 0x18},
    {0x00, 0x08, 0x1d, 0x3f, 0xff, 0x3f, 0x1d, 0x08},
    {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00},
    {0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff},
    {0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00},
    {0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff},
    {0xf0, 0xe0, 0xfe, 0xbf, 0x11, 0x11, 0x1f, 0x0e},
    {0x00, 0x72, 0xfa, 0x8f, 0x8f, 0xfa, 0x72, 0x00},
    {0xe0, 0xe0, 0xa0, 0xa0, 0xfe, 0xff, 0x07, 0x03},
    {0xfc, 0xfe, 0xa6, 0xa0, 0xa0, 0xfe, 0xff, 0x03},
    {0x99, 0x5a, 0x3c, 0xe7, 0xe7, 0x3c, 0x5a, 0x99},
    {0x00, 0x10, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe},
    {0x00, 0xfe, 0x7c, 0x7c, 0x38, 0x38, 0x10, 0x10},
    {0x00, 0x24, 0x66, 0xff, 0xff, 0x66, 0x24, 0x00},
    {0x00, 0xfa, 0xfa, 0x00, 0x00, 0xfa, 0xfa, 0x00},
    {0xfe, 0xfe, 0x80, 0xfe, 0xfe, 0x90, 0xf0, 0x60},
    {0x40, 0xc0, 0x9a, 0xbf, 0xa5, 0xfd, 0x5b, 0x02},
    {0x00, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x00},
    {0x01, 0x29, 0x6d, 0xff, 0xff, 0x6d, 0x29, 0x01},
    {0x00, 0x20, 0x60, 0xfe, 0xfe, 0x60, 0x20, 0x00},
    {0x00, 0x08, 0x0c, 0xfe, 0xfe, 0x0c, 0x08, 0x00},
    {0x00, 0x10, 0x38, 0x7c, 0x54, 0x10, 0x10, 0x10},
    {0x00, 0x10, 0x10, 0x10, 0x54, 0x7c, 0x38, 0x10},
    {0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x3c, 0x3c},
    {0x10, 0x38, 0x7c, 0x10, 0x10, 0x7c, 0x38, 0x10},
    {0x0c, 0x1c, 0x3c, 0x7c, 0x7c, 0x3c, 0x1c, 0x0c},
    {0x60, 0x70, 0x78, 0x7c, 0x7c, 0x78, 0x70, 0x60},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x60, 0xfa, 0xfa, 0x60, 0x00},
    {0x00, 0x00, 0xe0, 0xe0, 0x00, 0xe0, 0xe0, 0x00},
    {0x00, 0x28, 0xfe, 0xfe, 0x28, 0xfe, 0xfe, 0x28},
    {0x00, 0x00, 0x48, 0x5c, 0xd6, 0xd6, 0x74, 0x24},
    {0x00, 0x46, 0x66, 0x30, 0x18, 0x0c, 0x66, 0x62},
    {0x00, 0x12, 0x5e, 0xec, 0xba, 0xf2, 0x5e, 0x0c},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xe0, 0x20},
    {0x00, 0x00, 0x00, 0x82, 0xc6, 0x7c, 0x38, 0x00},
    {0x00, 0x00, 0x00, 0x38, 0x7c, 0xc6, 0x82, 0x00},
    {0x10, 0x54, 0x7c, 0x38, 0x38, 0x7c, 0x54, 0x10},
    {0x00, 0x00, 0x10, 0x10, 0x7c, 0x7c, 0x10, 0x10},
    {0x00, 0x00, 0x00, 0x00, 0x06, 0x07, 0x01, 0x00},
    {0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10},
    {0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00},
    {0x00, 0x80, 0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06},
    {0x00, 0x7c, 0xfe, 0xb2, 0x9a, 0x8e, 0xfe, 0x7c},
    {0x00, 0x00, 0x02, 0x02, 0xfe, 0xfe, 0x42, 0x02},
    {0x00, 0x00, 0x66, 0xf6, 0x92, 0x9a, 0xce, 0x46},
    {0x00, 0x00, 0x6c, 0xfe, 0x92, 0x92, 0xc6, 0x44},
    {0x00, 0x0a, 0xfe, 0xfe, 0xca, 0x68, 0x38, 0x18},
    {0x00, 0x00, 0x9c, 0xbe, 0xa2, 0xa2, 0xe6, 0xe4},
    {0x00, 0x00, 0x0c, 0x9e, 0x92, 0xd2, 0x7e, 0x3c},
    {0x00, 0x00, 0xe0, 0xf0, 0x9e, 0x8e, 0xc0, 0xc0},
    {0x00, 0x00, 0x6c, 0xfe, 0x92, 0x92, 0xfe, 0x6c},
    {0x00, 0x00, 0x78, 0xfc, 0x96, 0x92, 0xf2, 0x60},
    {0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x66, 0x67, 0x01, 0x00},
    {0x00, 0x00, 0x00, 0x82, 0xc6, 0x6c, 0x38, 0x10},
    {0x00, 0x00, 0x24, 0x24, 0x24, 0x24, 0x24, 0x24},
    {0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x82, 0x00},
    {0x00, 0x00, 0x60, 0xf0, 0x9a, 0x8a, 0xc0, 0x40},
    {0x00, 0x78, 0xf8, 0xba, 0xba, 0x82, 0xfe, 0x7c},
    {0x00, 0x00, 0x3e, 0x7e, 0xc8, 0xc8, 0x7e, 0x3e},
    {0x00, 0x6c, 0xfe, 0x92, 0x92, 0xfe, 0xfe, 0x82},
    {0x00, 0x44, 0xc6, 0x82, 0x82, 0xc6, 0x7c, 0x38},
    {0x00, 0x38, 0x7c, 0xc6, 0x82, 0xfe, 0xfe, 0x82},
    {0x00, 0xc6, 0x82, 0xba, 0x92, 0xfe, 0xfe, 0x82},
    {0x00, 0xc0, 0x80, 0xb8, 0x92, 0xfe, 0xfe, 0x82},
    {0x00, 0x4e, 0xce, 0x8a, 0x82, 0xc6, 0x7c, 0x38},
    {0x00, 0x00, 0xfe, 0xfe, 0x10, 0x10, 0xfe, 0xfe},
    {0x00, 0x00, 0x00, 0x82, 0xfe, 0xfe, 0x82, 0x00},
    {0x00, 0x80, 0xfc, 0xfe, 0x82, 0x02, 0x0e, 0x0c},
    {0x00, 0xc6, 0xee, 0x38, 0x10, 0xfe, 0xfe, 0x82},
    {0x00, 0x0e, 0x06, 0x02, 0x82, 0xfe, 0xfe, 0x82},
    {0x00, 0xfe, 0xfe, 0x70, 0x38, 0x70, 0xfe, 0xfe},
    {0x00, 0xfe, 0xfe, 0x18, 0x30, 0x60, 0xfe, 0xfe},
    {0x00, 0x38, 0x7c, 0xc6, 0x82, 0xc6, 0x7c, 0x38},
    {0x00, 0x60, 0xf0, 0x90, 0x92, 0xfe, 0xfe, 0x82},
    {0x00, 0x00, 0x7a, 0xfe, 0x8e, 0x84, 0xfc, 0x78},
    {0x00, 0x66, 0xfe, 0x98, 0x90, 0xfe, 0xfe, 0x82},
    {0x00, 0x00, 0x4c, 0xce, 0x9a, 0xb2, 0xf6, 0x64},
    {0x00, 0x00, 0xc0, 0x82, 0xfe, 0xfe, 0x82, 0xc0},
    {0x00, 0x00, 0xfe, 0xfe, 0x02, 0x02, 0xfe, 0xfe},
    {0x00, 0x00, 0xf8, 0xfc, 0x06, 0x06, 0xfc, 0xf8},
    {0x00, 0xfe, 0xfe, 0x0c, 0x18, 0x0c, 0xfe, 0xfe},
    {0x00, 0xc2, 0xe6, 0x3c, 0x18, 0x3c, 0xe6, 0xc2},
    {0x00, 0x00, 0xe0, 0xf2, 0x1e, 0x1e, 0xf2, 0xe0},
    {0x00, 0xce, 0xe6, 0xb2, 0x9a, 0x8e, 0xc6, 0xe2},
    {0x00, 0x00, 0x00, 0x82, 0x82, 0xfe, 0xfe, 0x00},
    {0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80},
    {0x00, 0x00, 0x00, 0xfe, 0xfe, 0x82, 0x82, 0x00},
    {0x00, 0x10, 0x30, 0x60, 0xc0, 0x60, 0x30, 0x10},
    {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
    {0x00, 0x00, 0x00, 0x20, 0xe0, 0xc0, 0x00, 0x00},
    {0x00, 0x02, 0x1e, 0x3c, 0x2a, 0x2a, 0x2e, 0x04},
    {0x00, 0x0c, 0x1e, 0x12, 0x12, 0xfc, 0xfe, 0x82},
    {0x00, 0x00, 0x14, 0x36, 0x22, 0x22, 0x3e, 0x1c},
    {0x00, 0x02, 0xfe, 0xfc, 0x92, 0x12, 0x1e, 0x0c},
    {0x00, 0x00, 0x18, 0x3a, 0x2a, 0x2a, 0x3e, 0x1c},
    {0x00, 0x00, 0x40, 0xc0, 0x92, 0xfe, 0x7e, 0x12},
    {0x00, 0x20, 0x3e, 0x1f, 0x25, 0x25, 0x3d, 0x19},
    {0x00, 0x1e, 0x3e, 0x20, 0x10, 0xfe, 0xfe, 0x82},
    {0x00, 0x00, 0x00, 0x02, 0xbe, 0xbe, 0x22, 0x00},
    {0x00, 0x00, 0xbe, 0xbf, 0x01, 0x01, 0x07, 0x06},
    {0x00, 0x22, 0x36, 0x1c, 0x08, 0xfe, 0xfe, 0x82},
    {0x00, 0x00, 0x00, 0x02, 0xfe, 0xfe, 0x82, 0x00},
    {0x00, 0x1e, 0x3e, 0x38, 0x1c, 0x18, 0x3e, 0x3e},
    {0x00, 0x00, 0x1e, 0x3e, 0x20, 0x20, 0x3e, 0x3e},
    {0x00, 0x00, 0x1c, 0x3e, 0x22, 0x22, 0x3e, 0x1c},
    {0x00, 0x18, 0x3c, 0x24, 0x25, 0x1f, 0x3f, 0x21},
    {0x00, 0x21, 0x3f, 0x1f, 0x25, 0x24, 0x3c, 0x18},
    {0x00, 0x18, 0x38, 0x20, 0x32, 0x1e, 0x3e, 0x22},
    {0x00, 0x00, 0x24, 0x2e, 0x2a, 0x2a, 0x3a, 0x12},
    {0x00, 0x00, 0x24, 0x22, 0xfe, 0x7c, 0x20, 0x00},
    {0x00, 0x02, 0x3e, 0x3c, 0x02, 0x02, 0x3e, 0x3c},
    {0x00, 0x00, 0x38, 0x3c, 0x06, 0x06, 0x3c, 0x38},
    {0x00, 0x3c, 0x3e, 0x0e, 0x1c, 0x0e, 0x3e, 0x3c},
    {0x00, 0x22, 0x36, 0x1c, 0x08, 0x1c, 0x36, 0x22},
    {0x00, 0x00, 0x3e, 0x3f, 0x05, 0x05, 0x3d, 0x39},
    {0x00, 0x00, 0x26, 0x32, 0x3a, 0x2e, 0x26, 0x32},
    {0x00, 0x00, 0x82, 0x82, 0xee, 0x7c, 0x10, 0x10},
    {0x00, 0x00, 0x00, 0xee, 0xee, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x10, 0x10, 0x7c, 0xee, 0x82, 0x82},
    {0x00, 0x80, 0xc0, 0x40, 0xc0, 0x80, 0xc0, 0x40},
    {0x00, 0x0e, 0x1e, 0x32, 0x62, 0x32, 0x1e, 0x0e},
    {0x00, 0x00, 0x52, 0xdf, 0x8d, 0x89, 0xf9, 0x70},
    {0x00, 0x02, 0x5e, 0x5e, 0x02, 0x02, 0x5e, 0x5c},
    {0x00, 0x00, 0x98, 0xba, 0xaa, 0x2a, 0x3e, 0x1c},
    {0x42, 0xde, 0xbe, 0xaa, 0xaa, 0xae, 0xc4, 0x40},
    {0x00, 0x02, 0x9e, 0xbe, 0x2a, 0x2a, 0xae, 0x84},
    {0x00, 0x02, 0x1e, 0x3e, 0x2a, 0xaa, 0xae, 0x84},
    {0x00, 0x02, 0x1e, 0x3e, 0xea, 0xea, 0x2e, 0x04},
    {0x00, 0x00, 0x02, 0x27, 0x25, 0x25, 0x3c, 0x18},
    {0x40, 0xd8, 0xba, 0xaa, 0xaa, 0xbe, 0xdc, 0x40},
    {0x00, 0x00, 0x98, 0xba, 0x2a, 0x2a, 0xbe, 0x9c},
    {0x00, 0x00, 0x18, 0x3a, 0x2a, 0xaa, 0xbe, 0x9c},
    {0x00, 0x00, 0x80, 0x82, 0x3e, 0x3e, 0xa2, 0x80},
    {0x00, 0x40, 0xc2, 0xbe, 0xbe, 0xa2, 0xc0, 0x40},
    {0x00, 0x00, 0x00, 0x02, 0x3e, 0xbe, 0xa2, 0x80},
    {0x00, 0x9e, 0xbe, 0x68, 0x48, 0x68, 0xbe, 0x9e},
    {0x00, 0x00, 0x0e, 0x1e, 0xd4, 0xd4, 0x1e, 0x0e},
    {0x00, 0x00, 0xa2, 0xaa, 0xaa, 0x3e, 0x3e, 0x22},
    {0x2a, 0x2a, 0x3e, 0x3e, 0x2a, 0x2a, 0x2e, 0x04},
    {0x00, 0x92, 0xfe, 0xfe, 0x90, 0xd0, 0x7e, 0x3e},
    {0x00, 0x00, 0x4c, 0xde, 0x92, 0x92, 0xde, 0x4c},
    {0x00, 0x00, 0x4c, 0x5e, 0x12, 0x12, 0x5e, 0x4c},
    {0x00, 0x00, 0x0c, 0x1e, 0x12, 0x52, 0x5e, 0x4c},
    {0x00, 0x02, 0x5e, 0xde, 0x82, 0x82, 0xde, 0x5c},
    {0x00, 0x02, 0x1e, 0x1e, 0x02, 0x42, 0x5e, 0x5c},
    {0x00, 0x00, 0x5e, 0x5f, 0x05, 0x05, 0x5d, 0x59},
    {0x80, 0x98, 0x3c, 0x66, 0x66, 0x3c, 0x98, 0x80},
    {0x00, 0x00, 0xbc, 0xbe, 0x02, 0x02, 0xbe, 0xbc},
    {0x00, 0x24, 0x24, 0xe7, 0xe7, 0x24, 0x3c, 0x18},
    {0x00, 0x04, 0x66, 0xc2, 0x92, 0xfe, 0x7e, 0x16},
    {0x00, 0x00, 0xd4, 0xf4, 0x3f, 0x3f, 0xf4, 0xd4},
    {0x05, 0x1f, 0x6f, 0xf4, 0x90, 0x90, 0xff, 0xff},
    {0x40, 0xc0, 0x90, 0xfe, 0x7f, 0x11, 0x03, 0x02},
    {0x00, 0x02, 0x9e, 0xbe, 0xaa, 0x2a, 0x2e, 0x04},
    {0x00, 0x00, 0x00, 0x82, 0xbe, 0xbe, 0x22, 0x00},
    {0x00, 0x00, 0x4c, 0x5e, 0x52, 0x12, 0x1e, 0x0c},
    {0x00, 0x02, 0x5e, 0x5e, 0x42, 0x02, 0x1e, 0x1c},
    {0x00, 0x00, 0x0e, 0x5e, 0x50, 0x50, 0x5e, 0x5e},
    {0x00, 0x00, 0xbe, 0xbe, 0x8c, 0x98, 0xbe, 0xbe},
    {0x00, 0x14, 0xf4, 0xf4, 0x94, 0xf4, 0x64, 0x00},
    {0x00, 0x00, 0x64, 0xf4, 0x94, 0xf4, 0x64, 0x00},
    {0x00, 0x00, 0x04, 0x06, 0xa2, 0xb2, 0x1e, 0x0c},
    {0x00, 0x00, 0x10, 0x10, 0x10, 0x10, 0x1c, 0x1c},
    {0x00, 0x00, 0x1c, 0x1c, 0x10, 0x10, 0x10, 0x10},
    {0x89, 0xdd, 0x77, 0x33, 0x18, 0x0c, 0xf6, 0xf2},
    {0x9f, 0xdf, 0x6e, 0x36, 0x18, 0x0c, 0xf6, 0xf2},
    {0x00, 0x00, 0x00, 0xde, 0xde, 0x00, 0x00, 0x00},
    {0x44, 0x6c, 0x38, 0x10, 0x44, 0x6c, 0x38, 0x10},
    {0x10, 0x38, 0x6c, 0x44, 0x10, 0x38, 0x6c, 0x44},
    {0x00, 0xaa, 0x00, 0x55, 0x00, 0xaa, 0x00, 0x55},
    {0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55},
    {0xee, 0xff, 0x55, 0xbb, 0xee, 0x55, 0xff, 0xbb},
    {0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0xff, 0xff, 0x08, 0x08, 0x08},
    {0x00, 0x00, 0x00, 0xff, 0xff, 0x28, 0x28, 0x28},
    {0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x08, 0x08},
    {0x00, 0x0f, 0x0f, 0x08, 0x0f, 0x0f, 0x08, 0x08},
    {0x00, 0x00, 0x00, 0x3f, 0x3f, 0x28, 0x28, 0x28},
    {0x00, 0xff, 0xff, 0x00, 0xef, 0xef, 0x28, 0x28},
    {0x00, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00},
    {0x00, 0x3f, 0x3f, 0x20, 0x2f, 0x2f, 0x28, 0x28},
    {0x00, 0xf8, 0xf8, 0x08, 0xe8, 0xe8, 0x28, 0x28},
    {0x00, 0xf8, 0xf8, 0x08, 0xf8, 0xf8, 0x08, 0x08},
    {0x00, 0x00, 0x00, 0xf8, 0xf8, 0x28, 0x28, 0x28},
    {0x00, 0x00, 0x00, 0x0f, 0x0f, 0x08, 0x08, 0x08},
    {0x08, 0x08, 0x08, 0xf8, 0xf8, 0x00, 0x00, 0x00},
    {0x08, 0x08, 0x08, 0xf8, 0xf8, 0x08, 0x08, 0x08},
    {0x08, 0x08, 0x08, 0x0f, 0x0f, 0x08, 0x08, 0x08},
    {0x08, 0x08, 0x08, 0xff, 0xff, 0x00, 0x00, 0x00},
    {0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08},
    {0x08, 0x08, 0x08, 0xff, 0xff, 0x08, 0x08, 0x08},
    {0x28, 0x28, 0x28, 0xff, 0xff, 0x00, 0x00, 0x00},
    {0x08, 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0x00},
    {0x28, 0xe8, 0xe8, 0x08, 0xf8, 0xf8, 0x00, 0x00},
    {0x28, 0x2f, 0x2f, 0x20, 0x3f, 0x3f, 0x00, 0x00},
    {0x28, 0xe8, 0xe8, 0x08, 0xe8, 0xe8, 0x28, 0x28},
    {0x28, 0x2f, 0x2f, 0x20, 0x2f, 0x2f, 0x28, 0x28},
    {0x28, 0xef, 0xef, 0x00, 0xff, 0xff, 0x00, 0x00},
    {0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28},
    {0x28, 0xef, 0xef, 0x00, 0xef, 0xef, 0x28, 0x28},
    {0x28, 0x28, 0x28, 0xe8, 0xe8, 0x28, 0x28, 0x28},
    {0x08, 0xf8, 0xf8, 0x08, 0xf8, 0xf8, 0x08, 0x08},
    {0x28, 0x28, 0x28, 0x2f, 0x2f, 0x28, 0x28, 0x28},
    {0x08, 0x0f, 0x0f, 0x08, 0x0f, 0x0f, 0x08, 0x08},
    {0x08, 0xf8, 0xf8, 0x08, 0xf8, 0xf8, 0x00, 0x00},
    {0x28, 0x28, 0x28, 0xf8, 0xf8, 0x00, 0x00, 0x00},
    {0x28, 0x28, 0x28, 0x3f, 0x3f, 0x00, 0x00, 0x00},
    {0x08, 0x0f, 0x0f, 0x08, 0x0f, 0x0f, 0x00, 0x00},
    {0x08, 0xff, 0xff, 0x08, 0xff, 0xff, 0x08, 0x08},
    {0x28, 0x28, 0x28, 0xff, 0xff, 0x28, 0x28, 0x28},
    {0x00, 0x00, 0x00, 0xf8, 0xf8, 0x08, 0x08, 0x08},
    {0x08, 0x08, 0x08, 0x0f, 0x0f, 0x00, 0x00, 0x00},
    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
    {0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f},
    {0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff},
    {0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00},
    {0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0},
    {0x00, 0x22, 0x36, 0x1c, 0x36, 0x22, 0x3e, 0x1c},
    {0x00, 0x00, 0x28, 0x7c, 0x54, 0x54, 0x7f, 0x3f},
    {0x00, 0x00, 0x60, 0x60, 0x40, 0x40, 0x7e, 0x7e},
    {0x00, 0x40, 0x7e, 0x7e, 0x40, 0x7e, 0x7e, 0x40},
    {0x00, 0x00, 0xc6, 0xc6, 0x92, 0xba, 0xee, 0xc6},
    {0x00, 0x20, 0x20, 0x3c, 0x3e, 0x22, 0x3e, 0x1c},
    {0x00, 0x78, 0x7c, 0x04, 0x04, 0x7e, 0x7f, 0x01},
    {0x00, 0x40, 0x60, 0x3e, 0x7e, 0x40, 0x60, 0x20},
    {0x00, 0x00, 0x99, 0xbd, 0xe7, 0xe7, 0xbd, 0x99},
    {0x00, 0x38, 0x7c, 0xd6, 0x92, 0xd6, 0x7c, 0x38},
    {0x00, 0x32, 0x7e, 0xce, 0x80, 0xce, 0x7e, 0x32},
    {0x00, 0x00, 0x9c, 0xbe, 0xf2, 0x52, 0x1e, 0x0c},
    {0x18, 0x3c, 0x24, 0x3c, 0x3c, 0x24, 0x3c, 0x18},
    {0x18, 0xbc, 0xe4, 0x7c, 0x3c, 0x26, 0x3f, 0x19},
    {0x00, 0x00, 0x00, 0x92, 0x92, 0xd6, 0x7c, 0x38},
    {0x00, 0x00, 0x7e, 0xfe, 0x80, 0x80, 0xfe, 0x7e},
    {0x00, 0x00, 0x54, 0x54, 0x54, 0x54, 0x54, 0x54},
    {0x00, 0x00, 0x22, 0x22, 0xfa, 0xfa, 0x22, 0x22},
    {0x00, 0x00, 0x02, 0x22, 0x72, 0xda, 0x8a, 0x02},
    {0x00, 0x00, 0x02, 0x8a, 0xda, 0x72, 0x22, 0x02},
    {0x60, 0xe0, 0x80, 0xff, 0x7f, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0xfe, 0xff, 0x01, 0x07, 0x06},
    {0x00, 0x00, 0x10, 0x10, 0xd6, 0xd6, 0x10, 0x10},
    {0x00, 0x48, 0x6c, 0x24, 0x6c, 0x48, 0x6c, 0x24},
    {0x00, 0x00, 0x60, 0xf0, 0x90, 0xf0, 0x60, 0x00},
    {0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00},
    {0x80, 0x80, 0xff, 0xff, 0x03, 0x0e, 0x0c, 0x08},
    {0x00, 0x00, 0x78, 0xf8, 0x80, 0xf8, 0xf8, 0x00},
    {0x00, 0x00, 0x00, 0x48, 0xe8, 0xb8, 0x98, 0x00},
    {0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00},
    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
  }
};

BOOLEAN
CSynthesizer::
Initialize()
/*++

Routine Description:

    Class initialization.

    Set the buffer the synthesizer generates images to.
    Override to do any additional processing you think is needed.

Arguments:

    none

Return Value:

    TRUE - success.

--*/
{
    PAGED_CODE();

    m_StartTime = KeQueryPerformanceCounter(&m_Frequency).QuadPart;

    //  Capture the working palette.
    //  Recast it to a point to an array of primaries.
    if( !(m_Colors = GetPalette()) )
    {
        return FALSE;
    }

    //  Clear the globals.  This occurs redundantly, but hey ...
    //  ... test output doesn't make sense if we don't do this.
    for( ULONG i=0; i<MAX_Attribute; i++ )
    {
        m_Attrib[i]=0;
    }

    //
    // Allocate a scratch buffer for the synthesizer.
    //
    NT_ASSERT(m_Length);
    if( !m_Length )
    {
        return FALSE;
    }

    m_Buffer = new (PagedPool) UCHAR[m_Length];
    NT_ASSERT(m_Buffer);
    if( !m_Buffer )
    {
        return FALSE;
    }

    //
    // Allocate a scratch buffer for the Gradient.
    //
    m_GradientBmp = new (PagedPool) CKsRgbQuad[m_Width * MAX_COLOR];
    NT_ASSERT(m_GradientBmp);
    if( !m_GradientBmp )
    {
        SAFE_DELETE_ARRAY( m_Buffer );
        return FALSE;
    }

    return TRUE;
}

LONGLONG
ConvertPerfTime(
    _In_    LONGLONG    Freq,
    _In_    LONGLONG    Time
)
{
    PAGED_CODE();

    LARGE_INTEGER   tL ;
    tL.QuadPart = Time;
    return KSCONVERT_PERFORMANCE_TIME( Freq, tL );
}

void
CSynthesizer::
Destroy()
/*++

Routine Description:

    Clean up from initialize.
  
    Note: A good place to generate synthesis stats.

Arguments:

    none

Return Value:

    void.

--*/
{
    PAGED_CODE();

    SAFE_DELETE_ARRAY( m_Buffer );
    SAFE_DELETE_ARRAY( m_GradientBmp );

    LONGLONG EndTime = KeQueryPerformanceCounter(NULL).QuadPart;
    LONGLONG FPS = ((LONGLONG)m_SynthesisCount * NANOSECONDS) / ( ConvertPerfTime( m_Frequency.QuadPart, (EndTime - m_StartTime) ) + (NANOSECONDS/2) );

    //  Report rendering times.
    DBG_TRACE( "%s(%d,%d)", m_FormatName, m_Width, m_Height );
    DBG_TRACE( "Synthesis Time - Total = %lld", ConvertPerfTime( m_Frequency.QuadPart, m_SynthesisTime ) );
    DBG_TRACE( "                 Count = %d", m_SynthesisCount );
    DBG_TRACE( "                 Avg   = %lld", ConvertPerfTime( m_Frequency.QuadPart, m_SynthesisCount ? m_SynthesisTime / m_SynthesisCount : 0 ) );
    DBG_TRACE( "   Commit Time - Total = %lld", ConvertPerfTime( m_Frequency.QuadPart, m_CommitTime ) );
    DBG_TRACE( "                 Count = %d", m_CommitCount );
    DBG_TRACE( "                 Avg   = %lld", ConvertPerfTime( m_Frequency.QuadPart, m_CommitCount ? m_CommitTime / m_CommitCount : 0 ) );
    DBG_TRACE( "                   FPS = %lld", FPS );
}

NTSTATUS
CSynthesizer::
SynthesizeBars()
/*++

Routine Description:

    Synthesize EIA-189-A standard color bars onto the Image.  The image
    in question is the current synthesis buffer.

Arguments:

    None

Return Value:

    success / failure

--*/
{
    PAGED_CODE();

    if( !m_Buffer )
    {
        return STATUS_INVALID_DEVICE_STATE;
    }

    const COLOR *CurColor = m_ColorBars;
    ULONG ColorCount = SIZEOF_ARRAY (m_ColorBars);

    //
    // Set the default cursor...
    //
    GetImageLocation (0, 0);

    //
    // Synthesize a single line.
    //
    PUCHAR ImageStart = m_Cursor;
    for (ULONG x = 0; x < m_Width; x++)
    {
        PutPixel (m_ColorBars [((x * ColorCount) / m_Width)]);
    }

    PUCHAR ImageEnd = m_Cursor;

    //
    // Copy the synthesized line to all subsequent lines.
    //
    for (ULONG line = 0; line < m_Height; line++)
    {
        GetImageLocation (0, line);

        RtlCopyMemory (
            m_Cursor,
            ImageStart,
            ImageEnd - ImageStart
        );
    }

    //  Paint the top left and top right registrations boxes.
    GetImageLocation(0,0);

    ImageStart = m_Cursor;
    for(ULONG x =0; x < m_Width; x++)
    {
        if(x < (m_Height/16))
        {
            PutPixel(g_TopLeft);
        }
        else if(x > (m_Width - (m_Height / 16)))
        {
            PutPixel(g_TopRight);
        }
        else
        {
            PutPixel (m_ColorBars [((x * ColorCount) / m_Width)]);
        }
    }

    ImageEnd = m_Cursor;

    for (ULONG line = 0; line < m_Height/16; line++)
    {
        GetImageLocation (0, line);

        RtlCopyMemory (
            m_Cursor,
            ImageStart,
            ImageEnd - ImageStart
        );
    }

    //  Paint the bottom left and bottom right registrations boxes.
    GetImageLocation(0, (15*m_Height) / 16);
    ImageStart = m_Cursor;
    for(ULONG x =0; x < m_Width; x++)
    {
        if(x < (m_Height/16))
        {
            PutPixel(g_BotLeft);
        }
        else if(x > (m_Width - (m_Height / 16)))
        {
            PutPixel(g_BotRight);
        }
        else
        {
            PutPixel (m_ColorBars [((x * ColorCount) / m_Width)]);
        }
    }

    ImageEnd = m_Cursor;

    for (ULONG line = 0; line < m_Height/16; line++)
    {
        GetImageLocation (0, line+(15*m_Height) / 16);

        RtlCopyMemory (
            m_Cursor,
            ImageStart,
            ImageEnd - ImageStart
        );
    }

    return STATUS_SUCCESS;
}

void
CSynthesizer::
EncodeNumber(
    _In_ ULONG LocY,
    _In_ UINT32 Number,
    _In_ COLOR LowColor,
    _In_ COLOR HighColor
)
/*
Routine Description:

    Overlays an encoded number over the synthesized image. The image buffer
    used is the set synthesis buffer. The pattern is scaled to fit the image.

Arguments:

    LocY -
        The row on the image to begin the overlay. This must
        be inside the image.

    Number -
        The number to encode

    LowColor -
        The color to represent 0 (a clear bit)

    HighColor -
        The color to represent 1 (a set bit)

Return Value:

    void

*/
{
    PAGED_CODE();

    if( !m_Buffer )
    {
        return;
    }

    NT_ASSERT(LocY <= m_Height);

    GetImageLocation(0, LocY);
    UINT32 mask = 0x1;

    PUCHAR ImageStart = m_Cursor;
    for(ULONG i = 0; i < 32; i++)
    {
        for(ULONG j = 0; j < m_Width/32; j++)
        {
            if(Number & mask)
            {
                PutPixel(HighColor);
            }
            else
            {
                PutPixel(LowColor);
            }
        }
        mask = mask << 1;
    }
    PUCHAR ImageEnd = m_Cursor;

    //
    // Copy the synthesized line to all subsequent lines.
    //
    for (ULONG line = 1; line < m_Height/16; line++)
    {
        RtlCopyMemory (
            GetImageLocation (0, line + LocY),
            ImageStart,
            ImageEnd - ImageStart
        );
    }
}

void
CSynthesizer::
OverlayText (
    _In_ ULONG LocX,
    _In_ ULONG LocY,
    _In_ ULONG Scaling,
    _In_ LPSTR Text,
    _In_ COLOR BgColor,
    _In_ COLOR FgColor
)
/*++

Routine Description:

    Overlay text onto the synthesized image.  Clip to fit the image
    if the overlay does not fit.  The image buffer used is the set
    synthesis buffer.

Arguments:

    LocX -
        The X location on the image to begin the overlay.  This MUST
        be inside the image or no text will be rendered.  
        POSITION_CENTER may be used to indicate horizontal centering.

    LocY -
        The Y location on the image to begin the overlay.  This MUST
        be inside the image or no text will be rendered.  
        POSITION_CENTER may be used to indicate vertical centering.

    Scaling -
        Normally, the overlay is done in an 8x8 font.  A scaling of
        2 indicates 16x16, 3 indicates 24x24 and so forth.

    Text -
        A null terminated character string containing the information to 
        overlay

    BgColor -
        The background color of the overlay window.  For transparency,
        indicate TRANSPARENT here.

    FgColor -
        The foreground color for the text overlay.

Return Value:

    None

--*/

{
    PAGED_CODE();

    //  Validate internal state.
    if( !m_Buffer )
    {
        return;
    }

    NT_ASSERT(  (LocX <= m_Width  || LocX == POSITION_CENTER) &&
                (LocY <= m_Height || LocY == POSITION_CENTER) &&
                Text !=nullptr &&
                (BgColor < MAX_COLOR || BgColor == TRANSPARENT) &&
                (FgColor < MAX_COLOR || FgColor == TRANSPARENT)
             );

    //  Validate parameters.
    if( !( (LocX <= m_Width  || LocX == POSITION_CENTER) &&
            (LocY <= m_Height || LocY == POSITION_CENTER) &&
            Text !=nullptr &&
            (BgColor < MAX_COLOR || BgColor == TRANSPARENT) &&
            (FgColor < MAX_COLOR || FgColor == TRANSPARENT) ) )
    {
        return;
    }

    size_t  StrLen = 0;
    PUCHAR   CurChar;

    //
    // Determine the character length of the string.
    //
    if( !NT_SUCCESS( RtlStringCchLengthA( Text, m_Width, &StrLen ) ) )
    {
        // Invalid parameter.
        return;
    }

    //
    // Determine the physical size of the string plus border.  There is
    // a definable NO_CHARACTER_SEPARATION.  If this is defined, there will
    // be no added space between font characters.  Otherwise, one empty pixel
    // column is added between characters.
    //
#ifndef NO_CHARACTER_SEPARATION
    ULONG LenX = (ULONG) ((StrLen * (((size_t)Scaling) << 3)) + 1 + StrLen);
#else // NO_CHARACTER_SEPARATION
    ULONG LenX = (ULONG) ((StrLen * (((size_t_)Scaling) << 3)) + 2);
#endif // NO_CHARACTER_SEPARATION

    ULONG LenY = 2 + (Scaling << 3);

    //
    // Adjust for center overlays.
    //
    // NOTE: If the overlay doesn't fit into the synthesis buffer, this
    // merely left aligns the overlay and clips off the right side.
    //
    if (LocX == POSITION_CENTER)
    {
        //LocX = min( 0, ((LONG)m_Width - (LONG)LenX) >> 1);
        if (LenX >= m_Width)
        {
            LocX = 0;
        }
        else
        {
            LocX = (m_Width - LenX) >> 1;
        }
    }

    if (LocY == POSITION_CENTER)
    {
        //LocY = min( 0, ((LONG)m_Width - (LONG)LenY) >> 1);
        if (LenY >= m_Height)
        {
            LocY = 0;
        }
        else
        {
            LocY = (m_Height - LenY) >> 1;
        }
    }

    //
    // Determine the amount of space available on the synthesis buffer.
    // We will clip anything that finds itself outside the synthesis buffer.
    //
    ULONG SpaceX = m_Width - LocX;
    ULONG SpaceY = m_Height - LocY;

    //
    // Set the default cursor position.
    //
    GetImageLocation (LocX, LocY);

    //
    // Overlay a background color row.
    //
    if( SpaceY )
    {
        if( BgColor != TRANSPARENT )
        {
            for (ULONG x = 0; x < LenX && x < SpaceX; x++)
            {
                PutPixel (BgColor);
            }
        }
        SpaceY--;
    }
    LocY++;

    //
    // Loop across each row of the image.
    //
    for (ULONG row = 0; row < 8 && SpaceY; row++)
    {
        //
        // Generate a line.
        //
        GetImageLocation (LocX, LocY++);

        PUCHAR ImageStart = m_Cursor;

        ULONG CurSpaceX = SpaceX;
        if (CurSpaceX)
        {
            PutPixel (BgColor);
            CurSpaceX--;
        }

        //
        // Generate the row'th row of the overlay.
        //
        CurChar = (PUCHAR) Text;
        while( *CurChar )
        {
            UCHAR CharBase = m_FontData [m_Rotation==AcpiPldRotation90][*CurChar++][row];
            for (ULONG mask = 0x80; mask && CurSpaceX; mask >>= 1)
            {
                for (ULONG scale = 0; scale < Scaling && CurSpaceX; scale++)
                {
                    if (CharBase & mask)
                    {
                        PutPixel (FgColor);
                    }
                    else
                    {
                        PutPixel (BgColor);
                    }
                    CurSpaceX--;
                }
            }

            //
            // Separate each character by one space.  Account for the border
            // space at the end by placing the separator after the last
            // character also.
            //
#ifndef NO_CHARACTER_SEPARATION
            if (CurSpaceX)
            {
                PutPixel (BgColor);
                CurSpaceX--;
            }
#endif // NO_CHARACTER_SEPARATION
        }

        //
        // If there is no separation character defined, account for the
        // border.
        //
#ifdef NO_CHARACTER_SEPARATION
        if (CurSpaceX)
        {
            PutPixel (BgColor);
            CurSpaceX--;
        }
#endif // NO_CHARACTER_SEPARATION


        PUCHAR ImageEnd = m_Cursor;
        //
        // Copy the line downward scale times.
        //
        for (ULONG scale = 1; scale < Scaling && SpaceY; scale++)
        {
            GetImageLocation (LocX, LocY++);
            RtlCopyMemory (m_Cursor, ImageStart, ImageEnd - ImageStart);
            SpaceY--;
        }
    }

    //
    // Add the bottom section of the overlay.
    //
    GetImageLocation (LocX, LocY);
    if (BgColor != TRANSPARENT && SpaceY)
    {
        for (ULONG x = 0; x < LenX && x < SpaceX; x++)
        {
            PutPixel (BgColor);
        }
    }
}

void
CSynthesizer::ApplyGradient(
    _In_ ULONG LocY,
    _In_ COLOR Gradient
)
/*++

Routine Description:

    Synthesize a horizontal gradient bar from a given color

Arguments:

    LocY -
        row

    Gradient -
        A starting color

Return Value:

    void

--*/
{
    PAGED_CODE();

    if( !m_Buffer )
    {
        return;
    }

    NT_ASSERT(LocY <= m_Height);

    PUCHAR Image = GetImageLocation(0, LocY);
    PUCHAR  RowBmp = reinterpret_cast<PUCHAR>(&m_GradientBmp[Gradient*m_Width]);
    ULONG   Stride = m_Width * sizeof(CKsRgbQuad);

    //
    // Copy the synthesized line to all lines.
    //
    for (ULONG line = 0; line < m_Height/16; line++)
    {
        RtlCopyMemory (
            Image,
            RowBmp,
            Stride
        );
        Image += Stride;
    }
}

//
//  Synthesize
//
//  Fill the image buffer with some base image. All h/w simulations will
//  call this function to generate a base image - even for jpeg.
//
NTSTATUS
CSynthesizer::
Synthesize()
/*++

Routine Description:

    Fill the image buffer with some base image. All h/w simulations will
    call this function to generate a base image.

Arguments:

    None

Return Value:

    Success / failure

--*/
{
    PAGED_CODE();

    if( !m_Buffer )
    {
        return STATUS_INVALID_DEVICE_STATE;
    }

    //
    // Generate a "time stamp" just to overlay it onto the capture image.
    // It makes it more exciting than bars that do nothing.
    //
    SynthesizeBars();

    ApplyGradient( (m_Height)/16, RED);
    ApplyGradient( (2*m_Height)/16, GREEN);
    ApplyGradient( (3*m_Height)/16, BLUE);
    ApplyGradient( (4*m_Height)/16, WHITE);

    EncodeNumber((5*m_Height)/16, (UINT32)m_Attrib[FrameNumber], BLACK, WHITE);
    EncodeNumber((6*m_Height)/16, (UINT32)m_Attrib[QpcTime], BLACK, WHITE);

    CHAR Text [256];
    (void)RtlStringCbPrintfA(Text, sizeof(Text), "Frame: %lld", m_Attrib[FrameNumber]);

    //
    // Overlay the frame # onto the scratch space image.
    //
    OverlayText (
        POSITION_CENTER,
        (m_Height - 28),
        1,
        Text,
        BLACK,
        TEXT_COLOR
    );

    //
    // Add a description of the frame type/width/height.
    //
    (void)RtlStringCbPrintfA(Text, sizeof(Text), "%s (%dx%d)", m_FormatName, m_Width, m_Height);
    OverlayText (
        0,
        (m_Height - 28),
        1,
        Text,
        TRANSPARENT,
        TEXT_COLOR
    );

    //
    // Add a description of the mounting.
    //
    (void)RtlStringCbPrintfA(Text, sizeof(Text), "%d\370 Mounting", DbgRotation2Degrees(m_Rotation));
    size_t len = 0;
    (void)RtlStringCchLengthA(Text, sizeof(Text), &len);
    OverlayText (
        (m_Width - (((ULONG)len*8))),    // right-adjust text.
        (m_Height - 28),
        1,
        Text,
        TRANSPARENT,
        TEXT_COLOR
    );

    return STATUS_SUCCESS;
}

void
CSynthesizer::PutPixel (
    COLOR Color
)
/*++

Routine Description:

    Place a pixel at the default cursor location.  The cursor location
    must be set via GetImageLocation(x, y).

Arguments:

    Color -
        The pixel color to render

Return Value:

    void

--*/
{
    PAGED_CODE();

    PKS_RGBQUAD &pPixel = (PKS_RGBQUAD &) m_Cursor;

    if (Color != TRANSPARENT)
    {
        *pPixel = CKsRgbQuad( m_Colors[Color][2], m_Colors[Color][1], m_Colors[Color][0] );
    }

    //  Next pixel
    pPixel++;
}

//
// PutPixel():
//
// Place a pixel at the default cursor location.  The cursor location
// must be set via GetImageLocation(x, y).
//
void
CSynthesizer::PutPixel (
    UCHAR colorR,
    UCHAR colorB,
    UCHAR colorG
)
/*++

Routine Description:

    Place a pixel at the default cursor location.  The cursor location
    must be set via GetImageLocation(x, y).

    TODO: Remove.  This function appears to be dead code.

Arguments:

    colorR -
        The first color primary of the pixel.

    colorB -
        The third color primary of the pixel.

    colorG -
        The second color primary of the pixel.


Return Value:

    void

--*/
{
    PAGED_CODE();

    PKS_RGBQUAD &pPixel = (PKS_RGBQUAD &) m_Cursor;

    *pPixel++ = CKsRgbQuad( colorR, colorG, colorB );
}


//
//  Synthesize
//
//  Fill the image buffer with some base image. All h/w simulations will
//  call this function to generate a base image - even for jpeg.
//
NTSTATUS
CSynthesizer::
DoSynthesize()
{
    PAGED_CODE();

    LARGE_INTEGER StartTime = {0};
    LARGE_INTEGER EndTime = {0};

    StartTime = KeQueryPerformanceCounter(NULL);

    NTSTATUS Status = Synthesize();

    m_SynthesisTime += KeQueryPerformanceCounter(NULL).QuadPart - StartTime.QuadPart;
    m_SynthesisCount++;

    return Status;
}

//
//  Commit
//
//  Copy (and reformat, if necessary) pixels from the internal scratch
//  buffer.  If the output format decimates chrominance, do it here.
//
_Success_(return > 0)
ULONG
CSynthesizer::
DoCommit(
    _Out_writes_bytes_(Size)
    PUCHAR  Buffer,
    _In_    ULONG   Size,
    _In_    ULONG   Stride
)
{
    PAGED_CODE();

    LARGE_INTEGER StartTime = KeQueryPerformanceCounter(NULL);

    ULONG   n = Commit( Buffer, Size, Stride );

    m_CommitTime += KeQueryPerformanceCounter(NULL).QuadPart - StartTime.QuadPart;
    m_CommitCount++;

    return n;
}

//
//  DoCommit
//
//  Note: The stride needs to be a function of the bits per pixel of the
//        OUTPUT format - not the format we store it in.  The class ctor
//        must initialize m_OutputStride to a default stride value.
//
_Success_(return > 0)
ULONG
CSynthesizer::
DoCommit(
    _Out_writes_bytes_(Size)
    PUCHAR  Buffer,
    _In_    ULONG   Size
)
{
    PAGED_CODE();

    LARGE_INTEGER StartTime = KeQueryPerformanceCounter(NULL);

    ULONG   n = Commit( Buffer, Size );

    m_CommitTime += KeQueryPerformanceCounter(NULL).QuadPart - StartTime.QuadPart;
    m_CommitCount++;

    return n;
}

#define CLEAR_HISTOGRAM( H )                \
    if( H )                                 \
    {                                       \
        RtlZeroMemory( H, 256*sizeof(*H) ); \
    }

#define BUMP_HISTOGRAM_PRIMARY( H, C )      \
    if( H )                                 \
    {                                       \
        H[C]++;                             \
    }

//
//  Histogram
//
//  Fill an array with histogram data.
//
void
CSynthesizer::
Histogram(
    _Out_writes_opt_(256)
    PULONG  HistogramP0,        //  rgbRed
    _Out_writes_opt_(256)
    PULONG  HistogramP1,        //  rgbGreen
    _Out_writes_opt_(256)
    PULONG  HistogramP2         //  rgbBlue
)
/*++

Routine Description:

    Fill array(s) with histogram data.

Arguments:

    HistogramP0 -
        Stats on the first primary.

    HistogramP1 -
        Stats on the second primary.

    HistogramP2 -
        Stats on the third primary.

Return Value:

    void

--*/
{
    PAGED_CODE();

    CLEAR_HISTOGRAM( HistogramP0 );
    CLEAR_HISTOGRAM( HistogramP1 );
    CLEAR_HISTOGRAM( HistogramP2 );

    ULONG row, col;

    for( row=0; row<m_Height; row++ )
    {
        PKS_RGBQUAD pPixel = (PKS_RGBQUAD) GetImageLocation(0, row);

        for( col=0; col<m_Width; col++ )
        {
            BUMP_HISTOGRAM_PRIMARY( HistogramP0, pPixel->rgbRed );
            BUMP_HISTOGRAM_PRIMARY( HistogramP1, pPixel->rgbGreen );
            BUMP_HISTOGRAM_PRIMARY( HistogramP2, pPixel->rgbBlue );
        }
    }
}
